package com.xiye.system.controller.role;

import com.xiye.common.controller.BaseController;
import com.xiye.common.entity.*;
import com.xiye.common.util.*;
import com.xiye.system.config.YmlConfig;
import com.xiye.system.service.menu.MenuService;
import com.xiye.system.service.role.RoleService;
import com.xiye.system.service.user.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONArray;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @Package com.xiye.system.controller.role
 * @Description 角色权限管理
 * @Author 西野
 * @Date 2018-07-06
 * @Version V1.0
 */
@RestController
@RequestMapping(value = "/role")
@Api(value = "/role", tags = "角色权限管理")
public class RoleController extends BaseController {

    String menuUrl = "role/list"; // 菜单地址(权限用)
    @Autowired
    private MenuService menuService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private UserService userService;
    @Autowired
    private YmlConfig ymlConfig;
    @Autowired
    private AmqpTemplate rabbitMQTemplate;

    /*
     * @Author 西野
     * @Date 2018-07-06 11:39:12
     * @Description 进入权限首页
     * @Param []
     * @Return java.lang.Object
     */
    @ApiOperation(value = "权限列表", notes = "根据ROLE_ID获取列表")
    @ApiImplicitParams({@ApiImplicitParam(name = "ROLE_ID", value = "根据传输的数值显示列表数据", required = true), @ApiImplicitParam(name = "showCount", value = "每页显示记录数"), @ApiImplicitParam(name = "totalPage", value = "总页数"), @ApiImplicitParam(name = "totalResult", value = "总记录数"), @ApiImplicitParam(name = "currentPage", value = "当前页"), @ApiImplicitParam(name = "currentResult", value = "当前记录起始索引"), @ApiImplicitParam(name = "entityOrField", value = "true:需要分页的地方，传入的参数就是Page实体；false:需要分页的地方，传入的参数所代表的实体拥有Page属性")})
    @RequestMapping(value = "/list", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
    public Result list(Page page) {
        PageData pd = this.getPageData();
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            if (pd.getString("ROLE_ID") == null || "".equals(pd.getString("ROLE_ID").trim())) {
                pd.put("ROLE_ID", "1"); // 默认列出第一组角色(初始设计系统用户和会员组不能删除)
            }
            PageData pd_new = new PageData();
            pd_new.put("ROLE_ID", "0");
            pd_new.put("TYPE", "1");
            pd.put("TYPE", "1");
            Page page_fpd = new Page();
            page_fpd.setPageData(pd_new);
            /*Page page_pd = new Page();*/
            page.setPageData(pd);
            List<PageData> roleList = roleService.listAllRolesByPId(page_fpd); // 列出组(页面横向排列的一级组)
            List<PageData> roleList_z = roleService.listAllRolesByPId(page); // 列出此组下架角色
            //pd = roleService.findObjectById(pd); // 取得点击的角色组(横排的)
            map.put("Page", page);
            map.put("roleList", JSONArray.fromObject(roleList));
            map.put("roleList_z", JSONArray.fromObject(roleList_z));
            map.put("QX", Jurisdiction.getHC());//按钮权限
            return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);
        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 10:14:37
     * @Description 保存新增角色
     * @Param []
     * @Return java.lang.Object
     */
    @ApiOperation(value = "保存新增角色", notes = "新增角色")
    @ApiImplicitParams({@ApiImplicitParam(name = "ROLE_NAME", value = "新名称", required = true), @ApiImplicitParam(name = "PARENT_ID", value = "新增组时传0；新增角色时传父节点的ROLE_ID", required = true)})
    @RequestMapping(value = "/add", method = RequestMethod.PUT, produces = "application/json;charset=utf-8")
    public Result add() {
        /*if (!Jurisdiction.buttonJurisdiction(menuUrl, "add")) {
            return null;
        } // 校验权限*/
        Map<String, Object> map = new HashMap<String, Object>();
        PageData pd = this.getPageData();
        try {
            String parent_id = pd.getString("PARENT_ID"); // 父类角色id
            pd.put("ROLE_ID", parent_id);
            if ("0".equals(parent_id)) {
                pd.put("RIGHTS", ""); // 菜单权限
            } else {
                String rights = roleService.findObjectById(pd).getString("RIGHTS");
                pd.put("RIGHTS", (null == rights) ? "" : rights); // 组菜单权限
            }
            String RNUMBER = "R" + DateUtil.getDays() + Tools.getRandomNum();
            pd.put("RNUMBER", RNUMBER); // 编码
            pd.put("ROLE_ID", this.get32UUID()); // 主键
            pd.put("ADD_QX", "0"); // 初始新增权限为否
            pd.put("DEL_QX", "0"); // 删除权限
            pd.put("EDIT_QX", "0"); // 修改权限
            pd.put("CHA_QX", "0"); // 查看权限
            roleService.add(pd);
            map.put("pd", pd);
            return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);
        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 10:00:26
     * @Description 修改组名称、修改角色名称
     * @Param []
     * @Return java.lang.Object
     */
    @ApiOperation(value = "修改角色名称", notes = "根据ROLE_ID修改组名称、修改角色名称")
    @ApiImplicitParams({@ApiImplicitParam(name = "ROLE_ID", value = "角色ID", required = true), @ApiImplicitParam(name = "ROLE_NAME", value = "新名称", required = true)})
    @RequestMapping(value = "/edit", method = RequestMethod.PUT, produces = "application/json;charset=utf-8")
    public Result edit() {
        /*if (!Jurisdiction.buttonJurisdiction(menuUrl, "edit")) {
            return null;
        } // 校验权限*/
        Map<String, Object> map = new HashMap<String, Object>();
        logBefore(logger, Jurisdiction.getUsername() + "修改角色");
        PageData pd = this.getPageData();
        try {
            roleService.edit(pd);
            return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);
        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 10:23:13
     * @Description 删除角色
     * @Param [ROLE_ID]
     * @Return java.lang.Object
     */
    @ApiOperation(value = "删除角色", notes = "根据ROLE_ID删除角色")
    @ApiImplicitParam(name = "ROLE_ID", value = "角色id", required = true)
    @RequestMapping(value = "/delete", method = RequestMethod.DELETE, produces = "application/json;charset=utf-8")
    public Result deleteRole() {
        /*if (!Jurisdiction.buttonJurisdiction(menuUrl, "del")) {
            return null;
        } // 校验权限*/
        Map<String, Object> map = new HashMap<String, Object>();
        logBefore(logger, Jurisdiction.getUsername() + "删除角色");
        PageData pd = this.getPageData();
        String ROLE_ID = pd.getString("ROLE_ID");
        try {
            List<Role> roleList_z = roleService.listAllRolesByPId(pd); // 列出此部门的所有下级
            if ("zhuche".equals(ROLE_ID) || roleList_z.size() > 0) {
                String msg = "下级有数据时or注册组角色，删除失败";
                return ResultUtil.setRowbackResut_entity(false, 200, msg, map);
            } else {
                List<PageData> userlist = userService.listAllUserByRoldId(pd); // 此角色下的用户
                if (userlist.size() > 0) { // 该角色有账号在使用不能删除
                    String msg = "该角色有账号在使用不能删除";
                    return ResultUtil.setRowbackResut_entity(false, 200, msg, map);
                } else {
                    roleService.deleteRoleById(ROLE_ID); // 执行删除
                    return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
                }
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);
        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 10:56:35
     * @Description 显示菜单列表ztree(菜单授权菜单)
     * @Param [model, ROLE_ID]
     * @Return java.lang.Object
     */
    @ApiOperation(value = "菜单权限", notes = "显示菜单列表ztree(菜单授权菜单),角色ID，Admin菜单权限传1")
    @ApiImplicitParam(name = "ROLE_ID", value = "角色id", required = true)
    @RequestMapping(value = "/menuqx", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
    public Result listAllMenu() {
        PageData pd = this.getPageData();
        Map<String, Object> map = new HashMap<String, Object>();
        String ROLE_ID = pd.getString("ROLE_ID");
        try {
            Role role = roleService.getRoleById(ROLE_ID); // 根据角色ID获取角色对象
            String roleRights = role.getRIGHTS(); // 取出本角色菜单权限
            List<Menu> menuList = menuService.listAllMenuQx("0"); // 获取所有菜单
            menuList = this.readMenu(menuList, roleRights); // 根据角色权限处理菜单权限状态(递归处理)
            menuList = this.manageMenu(menuList); // 处理前端iview的tree组件问题处理
            JSONArray jsonArray = JSONArray.fromObject(menuList);
            String json = jsonArray.toString();
            json = json.replaceAll("MENU_ID", "id").replaceAll("PARENT_ID", "pId").replaceAll("TITLE", "name").replaceAll("subMenu", "nodes").replaceAll("hasMenu", "checked");
            map.put("ROLE_ID", ROLE_ID);
            map.put("zTreeNodes", json);
            return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);
        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 11:26:42
     * @Description 保存角色菜单权限
     * @Param [ROLE_ID, menuIds, out]
     * @Return java.lang.Object
     */
    @ApiOperation(value = "保存菜单权限", notes = "保存角色菜单权限")
    @ApiImplicitParams({@ApiImplicitParam(name = "ROLE_ID", value = "角色ID", required = true), @ApiImplicitParam(name = "MENUIDS", value = "目录ID，例：27,29,42,127,128,129,57,130,131", required = true)})
    @RequestMapping(value = "/saveMenuqx", method = RequestMethod.PUT, produces = "application/json;charset=utf-8")
    public Result saveMenuqx() {
        /*if (!Jurisdiction.buttonJurisdiction(menuUrl, "edit")) {
        }*/ // 校验权限
        logBefore(logger, Jurisdiction.getUsername() + "修改菜单权限");
        PageData pd = this.getPageData();
        Map<String, Object> map = new HashMap<String, Object>();
        String ROLE_ID = pd.getString("ROLE_ID");
        String menuIds = pd.getString("MENUIDS");
        Role role = new Role();
        try {
            if (null != menuIds && !"".equals(menuIds.trim())) {
                BigInteger rights = RightsHelper.sumRights(Tools.str2StrArray(menuIds));// 用菜单ID做权处理
                role = roleService.getRoleById(ROLE_ID); // 通过id获取角色对象
                role.setRIGHTS(rights.toString());
                roleService.updateRoleRights(role); // 更新当前角色菜单权限
                pd.put("rights", rights.toString());
            } else {
                role.setRIGHTS("");
                role.setROLE_ID(ROLE_ID);
                roleService.updateRoleRights(role); // 更新当前角色菜单权限(没有任何勾选)
                pd.put("rights", "");
            }
            pd.put("ROLE_ID", ROLE_ID);
            if (!"1".equals(ROLE_ID)) { // 当修改admin权限时,不修改其它角色权限
                roleService.setAllRights(pd); // 更新此角色所有子角色的菜单权限
            }
            /*将权限发到消息队列中进行缓存*/
            rabbitMQTemplate.convertAndSend(Const.RIGHTS_QUEUE, ROLE_ID);
            return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);
        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 11:16:50
     * @Description 请求角色按钮授权页面(增删改查)
     * @Param [ROLE_ID, msg, model]
     * @Return java.lang.Object
     */
    @ApiOperation(value = "按钮权限", notes = "请求角色按钮授权页面(增删改查)")
    @ApiImplicitParams({@ApiImplicitParam(name = "ROLE_ID", value = "角色ID", required = true), @ApiImplicitParam(name = "MSG", value = "增加：add_qx；删除：del_qx；修改：edit_qx；查询：cha_qx", required = true)})
    @RequestMapping(value = "/b4Button", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
    public Result b4Button() {
        PageData pd = this.getPageData();
        Map<String, Object> map = new HashMap<String, Object>();
        String ROLE_ID = pd.getString("ROLE_ID");
        String msg = pd.getString("MSG");
        try {
            List<Menu> menuList = menuService.listAllMenuQx("0"); // 获取所有菜单
            Role role = roleService.getRoleById(ROLE_ID); // 根据角色ID获取角色对象
            String roleRights = "";
            switch (msg) {
                case "add_qx":
                    roleRights = role.getADD_QX(); // 新增权限
                    break;
                case "del_qx":
                    roleRights = role.getDEL_QX(); // 删除权限
                    break;
                case "edit_qx":
                    roleRights = role.getEDIT_QX(); // 修改权限
                    break;
                case "cha_qx":
                    roleRights = role.getCHA_QX(); // 查看权限
                    break;
                default:
                    break;
            }
            menuList = this.readMenu(menuList, roleRights); // 根据角色权限处理菜单权限状态(递归处理)
            JSONArray arr = JSONArray.fromObject(menuList);
            String json = arr.toString();
            json = json.replaceAll("MENU_ID", "id").replaceAll("PARENT_ID", "pId").replaceAll("TITLE", "name").replaceAll("subMenu", "nodes").replaceAll("hasMenu", "checked");
            map.put("ROLE_ID", ROLE_ID);
            map.put("zTreeNodes", json);
            return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);
        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 11:19:27
     * @Description 保存角色按钮权限
     * @Param [ROLE_ID, menuIds, msg, out]
     * @Return java.lang.Object
     */
    @ApiOperation(value = "保存按钮权限", notes = "保存角色按钮权限")
    @ApiImplicitParams({@ApiImplicitParam(name = "ROLE_ID", value = "角色ID", required = true), @ApiImplicitParam(name = "MENUIDS", value = "目录ID，例：27,29,42,127,128,129,57,130,131", required = true), @ApiImplicitParam(name = "MSG", value = "权限名--增加：add_qx；删除：del_qx；修改：edit_qx；查询：cha_qx", required = true)})
    @RequestMapping(value = "/saveB4Button", method = RequestMethod.PUT, produces = "application/json;charset=utf-8")
    public Result saveB4Button() {
        /*if (!Jurisdiction.buttonJurisdiction(menuUrl, "edit")) {
        }*/ // 校验权限
        //logBefore(logger, Jurisdiction.getUsername() + "修改" + msg + "权限");
        PageData pd = this.getPageData();
        Map<String, Object> map = new HashMap<String, Object>();
        String ROLE_ID = pd.getString("ROLE_ID");
        String menuIds = pd.getString("MENUIDS");
        String msg = pd.getString("MSG");
        try {
            if (null != menuIds && !"".equals(menuIds.trim())) {
                BigInteger rights = RightsHelper.sumRights(Tools.str2StrArray(menuIds));
                pd.put("value", rights.toString());
            } else {
                pd.put("value", "");
            }
            pd.put("ROLE_ID", ROLE_ID);
            roleService.saveB4Button(msg, pd);
            /*将权限发到消息队列中进行缓存*/
            rabbitMQTemplate.convertAndSend(Const.RIGHTS_QUEUE, ROLE_ID);
            return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return ResultUtil.setRowbackResut_entity(false, 500, ymlConfig.getServer_error(), map);

        }
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 09:39:43
     * @Description 修改角色开启或者关闭
     * @Param []
     * @Return java.lang.Object
     */
    @ApiOperation(value = "角色开关", notes = "修改角色开启或者关闭")
    @ApiImplicitParams({@ApiImplicitParam(name = "ROLE_ID", value = "角色ID", required = true), @ApiImplicitParam(name = "STATUS", value = "1：关闭；0：开启", required = true)})
    @RequestMapping(value = "/upStatus", method = RequestMethod.PUT, produces = "application/json;charset=utf-8")
    public Result upStatus() throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        PageData pd = this.getPageData();
        roleService.upStatus(pd);
        return ResultUtil.setRowbackResut_entity(true, 200, ymlConfig.getServer_success(), map);
    }

    /*
     * @Author 西野
     * @Date 2018-07-06 11:19:01
     * @Description 根据角色权限处理权限状态(递归处理);menuList：传入的总菜单;roleRights：加密的权限字符串
     * @Param [menuList, roleRights]
     * @Return java.util.List<com.xiye.common.entity.Menu>
     */
    public List<Menu> readMenu(List<Menu> menuList, String roleRights) {
        menuList.forEach(m -> {
            m.setHasMenu(RightsHelper.testRights(roleRights, m.getMENU_ID()));
            this.readMenu(m.getSubMenu(), roleRights); // 是：继续排查其子菜单
        });
        return menuList;
    }

    /*
     * @Author 西野
     * @Date 2018-08-31 10:26:32
     * @Description 处理角色权限数据冲突
     * @Param [menuList]
     * @Return java.util.List<com.xiye.common.entity.Menu>
     */
    public List<Menu> manageMenu(List<Menu> menuList) {
        /*
         * 前端iview的tree组件冲突
         * 父节点下若没有勾选全部子节点，虽然父节点属于半选中状态，checked=false
         * 获取不到他的父级，父级的父级数据（即，不算选中）。
         * 正常select，选择父节点和子节点时分开的，即选中父节点，不必勾选全部子节点
         * 为了解决冲突，递归判断所有节点的子节点是否有全部权限
         * 若有子节点没有被选中（即没有权限，则父节点选中状态置为false）
         */
        List<Menu> menuList_new = menuList;
        menuList_new.forEach(m -> {
            // 判断是否有子节点
            if (m.getSubMenu().size() > 0) {
                // 判断子节点中是否存在没有权限的子节点
                boolean b = this.treeMenuList(m.getSubMenu());
                if (!b) {
                    m.setHasMenu(false);
                }
            }
        });
        return menuList;
    }

    /*
     * @Author 西野
     * @Date 2018-08-31 10:38:36
     * @Description 排查是否含有没有权限的子节点
     * @Param [menuList]
     * @Return boolean
     */
    public boolean treeMenuList(List<Menu> menuList) {
        /* AtomicBoolean可以跨线程判断，Boolean则不行 */
        AtomicBoolean b = new AtomicBoolean(true);
        //遍历出父id等于参数的id，add进子节点集合
        menuList.forEach(m -> {
            // 若子节点中含有子节点，则递归继续排查
            if (m.getSubMenu().size() > 0) {
                b.set(this.treeMenuList(m.getSubMenu()));
            } else {
                if (!m.isHasMenu()) {
                    b.set(false);
                }
            }
        });
        return b.get();
    }
}
